﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

namespace NetduinoRemoteControlFake
{
    class RemoteControlListener
    {
        private int _port;
        private IRemoteControl _remoteControlHandler;
        public RemoteControlListener(int port, IRemoteControl handler)
        {
            _port = port;
            _remoteControlHandler = handler;
        }

        public void Listen()
        {
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://*:"+_port.ToString()+"/");

            try
            {
                listener.Start();
            }
            catch (Exception e)
            {
                Console.WriteLine("LISTEN ERROR " + e.Message + "\nTry to run as administrator");
                Console.ReadLine();
                Environment.Exit(0);
            }

            while (true)
            {
                HttpListenerContext c = listener.GetContext();
                Thread t = new Thread(new ThreadStart(delegate() { HandleContext(c); }));
                t.Start();
            }
        }

        private void HandleContext(HttpListenerContext c)
        {
            try
            {
                
                c.Response.Headers["CH_ControlType"] = c.Request.Headers["CH_ControlType"];

                switch (c.Request.Headers["CH_ControlType"])
                {
                    case "ping":
                        c.Response.Headers["CH_Result"] = _remoteControlHandler.Ping();
                        break;

                    case "fetchLatestData":
                        SetLatestDataHeaders(c);
                        c.Response.Headers["CH_Result"] = "OK"; // Last in case of exceptions
                        break;

                    case "fetchLatestDataAndStatus":
                        SetLatestDataHeaders(c);

                        SetStatusHeaders(c);

                        c.Response.Headers["CH_Result"] = "OK";
                        break;

                    case "controlCommand":
                        try
                        {
                            HandleControlCmd(c);
                            c.Response.Headers["CH_Result"] = "OK";
                        }catch
                        {
                            c.Response.Headers["CH_Result"] = "BAD REQUEST";
                        }
                        break;

                    default:
                        c.Response.Headers["CH_Result"] = "BAD REQUEST";
                        break;
                }

                c.Response.Close();

            }
            catch { }
        }

        private void SetLatestDataHeaders(HttpListenerContext c)
        {
            c.Response.Headers["CH_IndoorTemp"] = _remoteControlHandler.GetSensorData(SensorType.IndoorTemp).ToString().Replace(',', '.');
            c.Response.Headers["CH_OutdoorTemp"] = _remoteControlHandler.GetSensorData(SensorType.OutdoorTemp).ToString().Replace(',', '.');
            c.Response.Headers["CH_SolarHeaterTemp"] = _remoteControlHandler.GetSensorData(SensorType.SolarHeaterTemp).ToString().Replace(',', '.');
            c.Response.Headers["CH_AirFlow"] = _remoteControlHandler.GetSensorData(SensorType.AirFlow).ToString().Replace(',', '.');
        }

        private void SetStatusHeaders(HttpListenerContext c)
        {
            // Ordering important, due to interleavings
            int speed = _remoteControlHandler.GetSpeed();
            double toTemp = _remoteControlHandler.GetToTemp();
            int min = _remoteControlHandler.GetMin();
            Modes m = _remoteControlHandler.GetMode();
            c.Response.Headers["CH_Mode"] = m.ToString();
            switch (m)
            {
                case Modes.Auto:
                case Modes.Speed:
                    c.Response.Headers["CH_Speed"] = speed.ToString();
                    break;

                case Modes.SpeedTemp:
                    c.Response.Headers["CH_Speed"] = speed.ToString();
                    c.Response.Headers["CH_ToTemp"] = toTemp.ToString();
                    break;

                case Modes.SpeedTime:
                    c.Response.Headers["CH_Speed"] = speed.ToString();
                    c.Response.Headers["CH_Min"] = min.ToString();
                    break;
            }
        }

        private void HandleControlCmd(HttpListenerContext c)
        {
            string mode = c.Request.Headers["CH_ControlAction"];
            string speed = c.Request.Headers["CH_Speed"];
            string temp = c.Request.Headers["CH_ToTemp"];
            string time = c.Request.Headers["CH_Min"];

            switch(mode)
            {
                case "Auto":
                    _remoteControlHandler.SetModeAuto();
                    break;

                case "Speed":
                    _remoteControlHandler.SetModeSpeed(int.Parse(speed));
                    break;

                case "SpeedTemp":
                    _remoteControlHandler.SetModeSpeedTemp(int.Parse(speed), double.Parse(temp));
                    break;

                case "SpeedTime":
                    _remoteControlHandler.SetModeSpeedTime(int.Parse(speed), int.Parse(time));
                    break;
            }
        }
    }
}
